using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
using MasterNeverDown.EverythingIOT.Model;
using NModbus;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace MasterNeverDown.EverythingIOT.Modbus;

public class ModbusHostService(
    ILogger<ModbusHostService> logger,
    IServiceProvider serviceProvider,    
    IConnection? _messageConnection
)
    : BackgroundService
{
    private readonly ConcurrentDictionary<string, Timer> _timers = new();
    private IModel? _messageChannel;
    private EventingBasicConsumer consumer;
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        string queueName = "catalogEvents";
        logger.LogInformation("ModbusHostService is starting.");
        // _messageConnection = serviceProvider.GetRequiredService<IConnection>();
        _messageChannel = _messageConnection.CreateModel();
        _messageChannel.QueueDeclare(queue: queueName,
            durable: false,
            exclusive: false,
            autoDelete: false,
            arguments: null);
        consumer = new EventingBasicConsumer(_messageChannel);
        consumer.Received += ProcessMessageAsync;
        _messageChannel.BasicConsume(queue:  queueName,
            autoAck: true, 
            consumer: consumer);

        return Task.CompletedTask;
    }


    private void ProcessMessageAsync(object? sender, BasicDeliverEventArgs args)
    {
        string messagetext = Encoding.UTF8.GetString(args.Body.ToArray());
        logger.LogInformation("The message is: {text}", messagetext);
        var subscription = JsonSerializer.Deserialize<ModbusSubscription>(messagetext);
        ProcessModbusSubscriptionAsync(subscription);
    }

    private async Task ProcessModbusSubscriptionAsync(ModbusSubscription subscription)
    {
        var timer = new Timer(ReadModbusData!, subscription, TimeSpan.Zero, TimeSpan.FromSeconds(1));
        _timers[subscription.Host + subscription.Port + subscription.SlaveId + subscription.StartAddress] = timer;
        await Task.CompletedTask;
    }

    private void ReadModbusData(object state)
    {
        var subscription = (ModbusSubscription)state;
        try
        {
            using var client = new TcpClient(subscription.Host, subscription.Port);
            var factory = new ModbusFactory();
            var master = factory.CreateMaster(client);

            var registers = master.ReadHoldingRegisters(subscription.SlaveId, subscription.StartAddress,
                subscription.NumRegisters);

            for (var i = 0; i < registers.Length; i++)
            {
                logger.LogInformation(
                    $"DateTime:{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff} Register {subscription.StartAddress + i}: {registers[i]}");
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error reading Modbus data.");
        }
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("ModbusHostService is stopping.");
        await base.StopAsync(cancellationToken);
        consumer.Received -= ProcessMessageAsync;
        _messageChannel?.Dispose();
        foreach (var timer in _timers.Values)
        {
            timer.Change(Timeout.Infinite, 0);
            await timer.DisposeAsync();
        }

        _timers.Clear();
    }
}